package com.ruoyi.framework.aspectj

import com.ruoyi.common.utils.*
import com.ruoyi.framework.aspectj.lang.annotation.DataScope
import com.ruoyi.framework.security.context.PermissionContextHolder
import com.ruoyi.framework.web.domain.BaseEntity
import com.ruoyi.project.system.domain.SysUser
import org.apache.commons.lang3.StringUtils
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.*
import org.springframework.stereotype.Component

/**
 * 数据过滤处理
 *
 * @author ruoyi
 */
@Aspect
@Component
class DataScopeAspect {
    @Before("@annotation(controllerDataScope)")
    @Throws(Throwable::class)
    fun doBefore(point: JoinPoint, controllerDataScope: DataScope) {
        clearDataScope(point)
        handleDataScope(point, controllerDataScope)
    }

    protected fun handleDataScope(joinPoint: JoinPoint, controllerDataScope: DataScope) {
        // 获取当前的用户
        val loginUser = SecurityUtils.getLoginUser()
        if (com.ruoyi.common.utils.StringUtils.isNotNull(loginUser)) {
            val currentUser = loginUser.user!!
            // 如果是超级管理员，则不过滤数据
            if (com.ruoyi.common.utils.StringUtils.isNotNull(currentUser) && !currentUser.isAdmin) {
                val permission =
                    StringUtils.defaultIfEmpty(controllerDataScope.permission, PermissionContextHolder.getContext())
                dataScopeFilter(
                    joinPoint, currentUser, controllerDataScope.deptAlias,
                    controllerDataScope.userAlias, permission
                )
            }
        }
    }

    /**
     * 拼接权限sql前先清空params.dataScope参数防止注入
     */
    private fun clearDataScope(joinPoint: JoinPoint) {
        val params = joinPoint.args[0]
        if (com.ruoyi.common.utils.StringUtils.isNotNull(params) && params is BaseEntity) {
            params.params?.set(DATA_SCOPE, "")
        }
    }

    companion object {
        /**
         * 全部数据权限
         */
        const val DATA_SCOPE_ALL = "1"

        /**
         * 自定数据权限
         */
        const val DATA_SCOPE_CUSTOM = "2"

        /**
         * 部门数据权限
         */
        const val DATA_SCOPE_DEPT = "3"

        /**
         * 部门及以下数据权限
         */
        const val DATA_SCOPE_DEPT_AND_CHILD = "4"

        /**
         * 仅本人数据权限
         */
        const val DATA_SCOPE_SELF = "5"

        /**
         * 数据权限过滤关键字
         */
        const val DATA_SCOPE = "dataScope"

        /**
         * 数据范围过滤
         *
         * @param joinPoint 切点
         * @param user 用户
         * @param deptAlias 部门别名
         * @param userAlias 用户别名
         * @param permission 权限字符
         */
        fun dataScopeFilter(
            joinPoint: JoinPoint,
            user: SysUser,
            deptAlias: String?,
            userAlias: String?,
            permission: String?,
        ) {
            var sqlString = StringBuilder()
            val conditions: MutableList<String> = ArrayList()
            for (role in user.roles!!) {
                val dataScope = role.dataScope
                if (DATA_SCOPE_CUSTOM != dataScope && conditions.contains(dataScope)) {
                    continue
                }
                if (com.ruoyi.common.utils.StringUtils.isNotEmpty(permission) && com.ruoyi.common.utils.StringUtils.isNotEmpty(
                        role.permissions
                    ) && !role.permissions?.contains(permission)!!
                ) {
                    continue
                }
                when (dataScope) {
                    DATA_SCOPE_ALL -> {
                        sqlString = StringBuilder()
                        break
                    }

                    DATA_SCOPE_CUSTOM -> {
                        sqlString.append(
                            com.ruoyi.common.utils.StringUtils.format(
                                " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ",
                                deptAlias,
                                role.roleId
                            )
                        )
                    }

                    DATA_SCOPE_DEPT -> {
                        sqlString.append(
                            com.ruoyi.common.utils.StringUtils.format(
                                " OR {}.dept_id = {} ",
                                deptAlias,
                                user.deptId
                            )
                        )
                    }

                    DATA_SCOPE_DEPT_AND_CHILD -> {
                        sqlString.append(
                            com.ruoyi.common.utils.StringUtils.format(
                                " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
                                deptAlias, user.deptId, user.deptId
                            )
                        )
                    }

                    DATA_SCOPE_SELF -> {
                        if (StringUtils.isNotBlank(userAlias)) {
                            sqlString.append(
                                com.ruoyi.common.utils.StringUtils.format(
                                    " OR {}.user_id = {} ",
                                    userAlias,
                                    user.userId
                                )
                            )
                        } else {
                            // 数据权限为仅本人且没有userAlias别名不查询任何数据
                            sqlString.append(
                                com.ruoyi.common.utils.StringUtils.format(
                                    " OR {}.dept_id = 0 ",
                                    deptAlias
                                )
                            )
                        }
                    }
                }
                conditions.add(dataScope!!)
            }
            if (StringUtils.isNotBlank(sqlString.toString())) {
                val params = joinPoint.args[0]
                if (com.ruoyi.common.utils.StringUtils.isNotNull(params) && params is BaseEntity) {
                    params.params?.set(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")")
                }
            }
        }
    }
}
